<template>
  <div class="toolbar-container">
    <div class="toolbar-container-box">
      <div class="left-toolbar">
        <el-button type="text" @click="$emit('visible')">
          <i style="font-size: 18px" :class="visible?'el-icon-s-fold':'el-icon-s-unfold'"></i>
        </el-button>
        <el-button type="text" :disabled="undoDisabled" :title="i18nt('designer.toolbar.undoHint')"
                   @click="undoHistory">
          <svg-icon icon-class="undo"/>
        </el-button>
        <el-button type="text" :disabled="redoDisabled" :title="i18nt('designer.toolbar.redoHint')"
                   @click="redoHistory">
          <svg-icon icon-class="redo"/>
        </el-button>
        <!-- <el-button type="text" @click="scriptEditVisible=true">
          编辑脚本
        </el-button> -->
        <!--      <el-button type="text" @click="designer.startSelect = !designer.startSelect">
           {{ !designer.startSelect ? "选择" : "完成选择" }}组件
         </el-button>-->
        <!-- <el-button type="text" @click="saveSelfComponent">保存组件</el-button>

        <span style="font-size: 12px">{{
            designer.selfComponent.length > 0 ? `（已选择 ${designer.selfComponent.length} 个组件）` : ''
          }}</span> -->
      </div>
      <div class="center-toolbar">
        「{{ name }}」
      </div>
      <div class="right-toolbar">
        <div class="right-toolbar-con">
          <el-button-group>
            <el-button size="mini" v-if="showToolButton('clearDesignerButton')" @click="clearFormWidget">
              清空
            </el-button>
            <el-button size="mini" v-if="showToolButton('exportJsonButton')" @click="exportJson">
              保存
            </el-button>
            <el-button size="mini" v-if="showToolButton('previewFormButton')" @click="previewForm">预览</el-button>
          </el-button-group> &nbsp;

          <!--                <el-button v-if="showToolButton('importJsonButton')" type="text" @click="importJson">
                              导入JSON
                          </el-button>-->


                         <!-- <el-button v-if="showToolButton('exportCodeButton')" type="text" @click="exportCode">
                              导出代码
                          </el-button>
                          <el-button v-if="showToolButton('generateSFCButton')" type="text" @click="generateSFC">
                              <svg-icon icon-class="vue-sfc"/>
                              生成SFC
                          </el-button> -->
          <template v-for="(idx, slotName) in $slots">
            <slot :name="slotName"></slot>
          </template>
        </div>
      </div>
    </div>

    <!--预览-->
    <el-dialog title="预览页面" :visible.sync="showPreviewDialogFlag"
               v-if="showPreviewDialogFlag"
               :show-close="true" :close-on-click-modal="false" :close-on-press-escape="false" center v-dialog-drag
               :destroy-on-close="true" :append-to-body="true" class="small-padding-dialog preview-dialog" width="60%"
               :fullscreen="(layoutType === 'H5') || (layoutType === 'Pad')"
    >
      <div>
        <div class="form-render-wrapper" id="form-render-wrapper"
             :class="[layoutType === 'H5' ? 'h5-layout' : (layoutType === 'Pad' ? 'pad-layout' : '')]">
          <VFormRender v-if="showPreviewDialogFlag"
                       ref="preForm"
                       :script="pScript"
                       :form-json="formJson"
                       :form-data="testFormData"
                       :preview-state="true"
                       :option-data="testOptionData"
                       :global-dsv="designerDsv"
                       @appendButtonClick="testOnAppendButtonClick"
                       @buttonClick="testOnButtonClick"
                       @formChange="handleFormChange">
          </VFormRender>
        </div>
      </div>
      <code-editor v-model="testFunc" style="display: none"></code-editor>
      <div slot="footer" class="dialog-footer" style="text-align: right">
        <!-- <el-button v-if="false" type="primary" @click="resetForm">{{
            i18nt('designer.hint.resetForm')
          }}
        </el-button>
        <el-button v-if="false" type="primary" @click="setFormDisabled">{{
            i18nt('designer.hint.disableForm')
          }}
        </el-button>
        <el-button v-if="false" type="primary" @click="setFormEnabled">{{
            i18nt('designer.hint.enableForm')
          }}
        </el-button>
        <el-button type="" @click="showPreviewDialogFlag = false">{{ i18nt('designer.hint.closePreview') }}
        </el-button> -->
      </div>
    </el-dialog>

    <!--导入JSON-->
    <el-dialog :title="i18nt('designer.toolbar.importJson')" :visible.sync="showImportJsonDialogFlag"
               v-if="showImportJsonDialogFlag" :show-close="true" class="small-padding-dialog" center append-to-body
               v-dialog-drag
               :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
      <el-alert type="info" :title="i18nt('designer.hint.importJsonHint')" show-icon
                class="alert-padding"></el-alert>
      <code-editor :mode="'json'" :readonly="false" v-model="importTemplate"></code-editor>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="doJsonImport">
          {{ i18nt('designer.hint.import') }}
        </el-button>
        <el-button @click="showImportJsonDialogFlag = false">
          {{ i18nt('designer.hint.cancel') }}
        </el-button>
      </div>
    </el-dialog>

    <!--导出JSON-->
    <el-dialog :title="i18nt('designer.toolbar.exportJson')" :visible.sync="showExportJsonDialogFlag"
               v-if="showExportJsonDialogFlag" :show-close="true" class="small-padding-dialog" center append-to-body
               v-dialog-drag
               :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
      <code-editor :mode="'json'" :readonly="true" v-model="jsonContent"></code-editor>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" class="copy-json-btn" :data-clipboard-text="jsonRawContent"
                   @click="copyFormJson">
          {{ i18nt('designer.hint.copyJson') }}
        </el-button>
        <el-button @click="saveFormJson">{{ i18nt('designer.hint.saveFormJson') }}</el-button>
        <el-button type="" @click="showExportJsonDialogFlag = false">
          {{ i18nt('designer.hint.closePreview') }}
        </el-button>
      </div>
    </el-dialog>

    <!--导出代码-->
    <el-dialog :title="i18nt('designer.toolbar.exportCode')" :visible.sync="showExportCodeDialogFlag"
               v-if="showExportCodeDialogFlag" :show-close="true" class="small-padding-dialog" center append-to-body
               v-dialog-drag
               width="65%" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
      <el-tabs type="border-card" class="no-box-shadow no-padding" v-model="activeCodeTab">
        <el-tab-pane label="Vue" name="vue">
          <code-editor :mode="'html'" :readonly="true" v-model="vueCode" :user-worker="false"></code-editor>
        </el-tab-pane>
        <el-tab-pane label="HTML" name="html">
          <code-editor :mode="'html'" :readonly="true" v-model="htmlCode" :user-worker="false"></code-editor>
        </el-tab-pane>
      </el-tabs>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" class="copy-vue-btn" :data-clipboard-text="vueCode" @click="copyVueCode">
          {{ i18nt('designer.hint.copyVueCode') }}
        </el-button>
        <el-button type="primary" class="copy-html-btn" :data-clipboard-text="htmlCode" @click="copyHtmlCode">
          {{ i18nt('designer.hint.copyHtmlCode') }}
        </el-button>
        <el-button @click="saveVueCode">{{ i18nt('designer.hint.saveVueCode') }}</el-button>
        <el-button @click="saveHtmlCode">{{ i18nt('designer.hint.saveHtmlCode') }}</el-button>
        <el-button @click="showExportCodeDialogFlag = false">
          {{ i18nt('designer.hint.closePreview') }}
        </el-button>
      </div>
    </el-dialog>

    <!--生成SFC-->
    <el-dialog :title="i18nt('designer.toolbar.generateSFC')" :visible.sync="showExportSFCDialogFlag"
               v-if="showExportSFCDialogFlag" :show-close="true" class="small-padding-dialog" center append-to-body
               v-dialog-drag
               width="65%" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
      <el-tabs type="border-card" class="no-box-shadow no-padding" v-model="activeSFCTab">
        <el-tab-pane label="Vue2" name="vue2">
          <code-editor :mode="'html'" :readonly="true" v-model="sfcCode" :user-worker="false"></code-editor>
        </el-tab-pane>
        <el-tab-pane label="Vue3" name="vue3">
          <code-editor :mode="'html'" :readonly="true" v-model="sfcCodeV3" :user-worker="false"></code-editor>
        </el-tab-pane>
      </el-tabs>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" class="copy-vue2-sfc-btn" :data-clipboard-text="sfcCode" @click="copyV2SFC">
          {{ i18nt('designer.hint.copyVue2SFC') }}
        </el-button>
        <el-button type="primary" class="copy-vue3-sfc-btn" :data-clipboard-text="sfcCodeV3" @click="copyV3SFC">
          {{ i18nt('designer.hint.copyVue3SFC') }}
        </el-button>
        <el-button @click="saveV2SFC">{{ i18nt('designer.hint.saveVue2SFC') }}</el-button>
        <el-button @click="saveV3SFC">{{ i18nt('designer.hint.saveVue3SFC') }}</el-button>
        <el-button type="" @click="showExportSFCDialogFlag = false">
          {{ i18nt('designer.hint.closePreview') }}
        </el-button>
      </div>
    </el-dialog>

    <!--编辑脚本-->
    <script-edit ref="scriptEdit" :designer.sync="designer" :visible.sync="scriptEditVisible"></script-edit>
  </div>
</template>

<script>
import VFormRender from '@/components/form-render/index'
import CodeEditor from '@/components/code-editor/index'
import Clipboard from 'clipboard'
import {
  deepClone,
  copyToClipboard,
  generateId,
  getQueryParam,
  addWindowResizeHandler
} from "@/utils/util"
import i18n from '@/utils/i18n'
import {generateCode} from "@/utils/code-generator";
import {genSFC} from "@/utils/sfc-generator";
import loadBeautifier from "@/utils/beautifierLoader";
import {saveAs} from 'file-saver'
import SvgIcon from '@/components/svg-icon'
import ScriptEdit from "@/components/form-designer/toolbar-panel/scriptEdit.vue";

export default {
  name: "ToolbarPanel",
  mixins: [i18n],
  components: {
    ScriptEdit,
    VFormRender,
    CodeEditor,
    Clipboard,
    SvgIcon,
  },
  props: {
    designer: Object,
    globalDsv: {
      type: Object,
      default: () => ({})
    },
    name: {
      type: String,
      default: ''
    },
    visible: Boolean
  },
  inject: ['getDesignerConfig'],
  data() {
    return {
      designerConfig: this.getDesignerConfig(),

      toolbarWidth: 420,
      showPreviewDialogFlag: false,
      showImportJsonDialogFlag: false,
      showExportJsonDialogFlag: false,
      showExportCodeDialogFlag: false,
      showExportSFCDialogFlag: false,
      scriptEditVisible: false,

      nodeTreeData: [],

      testFunc: '',
      importTemplate: '',
      jsonContent: '',
      jsonRawContent: '',

      formDataJson: '',
      formDataRawJson: '',

      vueCode: '',
      htmlCode: '',

      sfcCode: '',
      sfcCodeV3: '',

      activeCodeTab: 'vue',
      activeSFCTab: 'vue2',

      testFormData: {
        // 'userName': '666888',
        // 'productItems': [
        //   {'pName': 'iPhone12', 'pNum': 10},
        //   {'pName': 'P50', 'pNum': 16},
        // ]

        'select62173': 2,
      },
      testOptionData: {
        'select62173': [
          {label: '01', value: 1},
          {label: '22', value: 2},
          {label: '333', value: 3},
        ],

        'select001': [
          {label: '辣椒', value: 1},
          {label: '菠萝', value: 2},
          {label: '丑橘子', value: 3},
        ],
      },

      pScript: {
        data: {},
        methods: {}
      },
    }
  },
  computed: {
    formJson() {
      return {
        dataSource: deepClone(this.designer.dataSource),
        widgetList: deepClone(this.designer.widgetList),
        formConfig: deepClone(this.designer.formConfig),
        pageScript: deepClone(this.designer.pageScript),
        templateScript: deepClone(this.designer.templateScript),
      }
    },

    undoDisabled() {
      return !this.designer.undoEnabled()
    },

    redoDisabled() {
      return !this.designer.redoEnabled()
    },

    layoutType() {
      return this.designer.getLayoutType()
    },

    designerDsv() {
      return this.globalDsv
    }

  },
  mounted() {
    let maxTBWidth = this.designerConfig.toolbarMaxWidth || 420
    let minTBWidth = this.designerConfig.toolbarMinWidth || 300
    let newTBWidth = window.innerWidth - 260 - 300 - 320 - 80
    this.toolbarWidth = newTBWidth >= maxTBWidth ? maxTBWidth : (newTBWidth <= minTBWidth ? minTBWidth : newTBWidth)
    addWindowResizeHandler(() => {
      this.$nextTick(() => {
        let newTBWidth2 = window.innerWidth - 260 - 300 - 320 - 80
        this.toolbarWidth = newTBWidth2 >= maxTBWidth ? maxTBWidth : (newTBWidth2 <= minTBWidth ? minTBWidth : newTBWidth2)
      })
    })
  },
  methods: {

    initScript(s) {
      if (s.data) {
        this.pScript.data = JSON.parse(s.data);
      }

      if (s.methods) {
        s.methods.forEach(item => {
          let obj = {};
          obj[item.funName] = new Function("arguments", item.funBody);
          Object.assign(this.pScript.methods, obj);
        })
      }
    },
    /*
    * 加载自定义组件脚本及变量 废弃⚠️
    * */
    initTempScript(script) {
      if (!script || Object.keys(script).length === 0) {
        return;
      }
      let obj = {};
      for (const key in script) {
        let s = script[key];

        if (s.data) {
          obj[key] = JSON.parse(s.data);
        } else {
          obj[key] = {};
        }

        if (s.methods) {
          s.methods.forEach(item => {
            let o = {};
            item.funBody = item.funBody.replaceAll("this", "this." + key)
            o[item.funName] = new Function("arguments", item.funBody);
            Object.assign(obj[key], o);
          })
        }
        Object.assign(this.pScript.data, obj)
      }
    },

    showToolButton(configName) {
      if (this.designerConfig[configName] === undefined) {
        return true
      }

      return !!this.designerConfig[configName]
    },

    undoHistory() {
      this.designer.undoHistoryStep()
    },

    redoHistory() {
      this.designer.redoHistoryStep()
    },

    clearFormWidget() {
      this.designer.clearDesigner()
      this.designer.formWidget.clearWidgetRefList()
    },
    previewForm() {
      this.initScript(this.formJson.pageScript)
      this.showPreviewDialogFlag = true;
    },

    saveAsFile(fileContent, defaultFileName) {
      this.$prompt(this.i18nt('designer.hint.fileNameForSave'), this.i18nt('designer.hint.saveFileTitle'), {
        inputValue: defaultFileName,
        closeOnClickModal: false,
        inputPlaceholder: this.i18nt('designer.hint.fileNameInputPlaceholder')
      }).then(({value}) => {
        if (!value) {
          value = defaultFileName
        }

        if (getQueryParam('vscode') == 1) {
          this.vsSaveFile(value, fileContent)
          return
        }

        const fileBlob = new Blob([fileContent], {type: 'text/plain;charset=utf-8'})
        saveAs(fileBlob, value)
      }).catch(() => {
        //
      })
    },

    vsSaveFile(fileName, fileContent) {
      const msgObj = {
        cmd: 'writeFile',
        data: {
          fileName,
          code: fileContent
        }
      }
      window.parent.postMessage(msgObj, '*')
    },

    importJson() {
      this.importTemplate = JSON.stringify(this.designer.getImportTemplate(), null, '  ')
      this.showImportJsonDialogFlag = true

    },

    doJsonImport() {
      try {
        let importObj = JSON.parse(this.importTemplate)
        this.designer.loadFormJson(importObj)

        this.showImportJsonDialogFlag = false
        this.$message.success(this.i18nt('designer.hint.importJsonSuccess'))

        this.designer.emitHistoryChange()

        this.designer.emitEvent('form-json-imported', [])
      } catch (ex) {
        this.$message.error(ex + '')
      }
    },

    exportJson() {
      let widgetList = deepClone(this.designer.widgetList)
      let formConfig = deepClone(this.designer.formConfig)
      let dataSource = deepClone(this.designer.dataSource)
      let dataSourceMap = deepClone(this.designer.dataSourceMap)
      let pageScript = deepClone(this.designer.pageScript)
      let templateScript = deepClone(this.designer.templateScript)

      for (const key in dataSourceMap) {
        dataSourceMap[key] = [];
      }
      this.$emit("saveJson", {widgetList, formConfig, dataSource, dataSourceMap, pageScript, templateScript})
    },

    copyFormJson(e) {
      copyToClipboard(this.jsonRawContent, e,
          this.$message,
          this.i18nt('designer.hint.copyJsonSuccess'),
          this.i18nt('designer.hint.copyJsonFail')
      )
    },

    saveFormJson() {
      this.saveAsFile(this.jsonContent, `vform${generateId()}.json`)
    },

    exportCode() {
      this.vueCode = generateCode(this.formJson)
      this.htmlCode = generateCode(this.formJson, 'html')
      this.showExportCodeDialogFlag = true
    },

    copyVueCode(e) {
      copyToClipboard(this.vueCode, e,
          this.$message,
          this.i18nt('designer.hint.copyVueCodeSuccess'),
          this.i18nt('designer.hint.copyVueCodeFail')
      )
    },

    copyHtmlCode(e) {
      copyToClipboard(this.htmlCode, e,
          this.$message,
          this.i18nt('designer.hint.copyHtmlCodeSuccess'),
          this.i18nt('designer.hint.copyHtmlCodeFail')
      )
    },

    saveVueCode() {
      this.saveAsFile(this.vueCode, `vform${generateId()}.vue`)
    },

    saveHtmlCode() {
      this.saveAsFile(this.htmlCode, `vform${generateId()}.html`)
    },

    generateSFC() {
      loadBeautifier(beautifier => {
        this.sfcCode = genSFC(this.designer.formConfig, this.designer.widgetList, beautifier, false, this.designer.dataSource)
        this.sfcCodeV3 = genSFC(this.designer.formConfig, this.designer.widgetList, beautifier, true)
        this.showExportSFCDialogFlag = true
      })
    },

    copyV2SFC(e) {
      copyToClipboard(this.sfcCode, e,
          this.$message,
          this.i18nt('designer.hint.copySFCSuccess'),
          this.i18nt('designer.hint.copySFCFail')
      )
    },

    copyV3SFC(e) {
      copyToClipboard(this.sfcCodeV3, e,
          this.$message,
          this.i18nt('designer.hint.copySFCSuccess'),
          this.i18nt('designer.hint.copySFCFail')
      )
    },

    saveV2SFC() {
      this.saveAsFile(this.sfcCode, `vformV2-${generateId()}.vue`)
    },

    saveV3SFC() {
      this.saveAsFile(this.sfcCodeV3, `vformV3-${generateId()}.vue`)
    },

    copyFormDataJson(e) {
      copyToClipboard(this.formDataRawJson, e,
          this.$message,
          this.i18nt('designer.hint.copyJsonSuccess'),
          this.i18nt('designer.hint.copyJsonFail')
      )
    },

    saveFormData() {
      this.saveAsFile(this.htmlCode, `formData${generateId()}.json`)
    },

    resetForm() {
      this.$refs['preForm'].resetForm()
    },

    setFormDisabled() {
      this.$refs['preForm'].disableForm()
    },

    setFormEnabled() {
      this.$refs['preForm'].enableForm()
    },

    handleFormChange(fieldName, newValue, oldValue, formModel) {
    },

    testOnAppendButtonClick(clickedWidget) {
    },

    testOnButtonClick(button) {
    },
  }
}
</script>

<style lang="scss" scoped>
.toolbar-container {
  width: 100%;

  .toolbar-container-box {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    flex-wrap: nowrap;
  }

  //min-width: 728px;  /* 解决工具按钮栏换行的问题 */
  /* 上一行css有问题，当窗口宽度不足时会把按钮挤出到右边的属性设置区，弃之！ */
}

.left-toolbar {
  font-size: 16px;
  display: flex;
  flex-wrap: nowrap;
}

.center-toolbar {
  line-height: 44px;
}

.right-toolbar {
  // float: right;
  //width: 420px;
  text-align: right;
  overflow: hidden;

  .right-toolbar-con {
    text-align: left;
    padding: calc((44px - 30px) / 2) 0;
    //width: 600px;
  }

  ::v-deep .el-button--text {
    font-size: 14px !important;
  }
}

.el-button i {
  margin-right: 3px;
}

.preview-dialog {
  background-color: rgba(0, 0, 0, .9);
}

.small-padding-dialog {
  ::v-deep .el-dialog__header {
    //padding-top: 3px;
    //padding-bottom: 3px;
    background: #f1f2f3;
    border-bottom: 1px solid #ccc;
    text-align: left;
  }

  ::v-deep .el-dialog__body {
    padding: 12px 15px 12px 15px;

    .el-alert.alert-padding {
      padding: 0 10px;
    }
  }

  ::v-deep .ace-container {
    border: 1px solid #DCDFE6;
  }
}

.dialog-title-light-bg {
  ::v-deep .el-dialog__header {
    background: #f1f2f3;
  }
}

.no-box-shadow {
  box-shadow: none;
}

.no-padding.el-tabs--border-card {
  ::v-deep .el-tabs__content {
    padding: 0;
  }
}

.form-render-wrapper {
  //height: calc(100vh - 142px);
  //all: revert !important; /* 防止表单继承el-dialog等外部样式，未生效，原因不明？？ */
}

.form-render-wrapper.h5-layout {
  margin: 0 auto;
  width: 420px;
  border-radius: 15px;
  //border-width: 10px;
  box-shadow: 0 0 1px 10px #495060;
  height: calc(100vh - 142px);
  overflow-y: auto;
  overflow-x: hidden;
}

.form-render-wrapper.pad-layout {
  margin: 0 auto;
  width: 960px;
  border-radius: 15px;
  //border-width: 10px;
  box-shadow: 0 0 1px 10px #495060;
  height: calc(100vh - 142px);
  overflow-y: auto;
  overflow-x: hidden;
}

.node-tree-drawer ::v-deep {
  .el-drawer {
    padding: 10px;
    overflow: auto;
  }

  .el-drawer__header {
    margin-bottom: 12px;
    padding: 5px 5px 0;
  }

  .el-drawer__body {
    padding-left: 5px;
  }
}

/*.node-tree-scroll-bar {*/
/*  height: 100%;*/
/*  overflow: auto;*/
/*}*/

.node-tree ::v-deep {
  .el-tree > .el-tree-node:after {
    border-top: none;
  }

  .el-tree-node {
    position: relative;
    padding-left: 12px;
  }

  .el-tree-node__content {
    padding-left: 0 !important;
  }

  .el-tree-node__expand-icon.is-leaf {
    display: none;
  }

  .el-tree-node__children {
    padding-left: 12px;
    overflow: visible !important; /* 加入此行让el-tree宽度自动撑开，超出宽度el-draw自动出现水平滚动条！ */
  }

  .el-tree-node :last-child:before {
    height: 38px;
  }

  .el-tree > .el-tree-node:before {
    border-left: none;
  }

  .el-tree > .el-tree-node:after {
    border-top: none;
  }

  .el-tree-node:before {
    content: "";
    left: -4px;
    position: absolute;
    right: auto;
    border-width: 1px;
  }

  .el-tree-node:after {
    content: "";
    left: -4px;
    position: absolute;
    right: auto;
    border-width: 1px;
  }

  .el-tree-node:before {
    border-left: 1px dashed #4386c6;
    bottom: 0px;
    height: 100%;
    top: -10px;
    width: 1px;
  }

  .el-tree-node:after {
    border-top: 1px dashed #4386c6;
    height: 20px;
    top: 12px;
    width: 16px;
  }

  .el-tree-node.is-current > .el-tree-node__content {
    background: #c2d6ea !important;
  }

  .el-tree-node__expand-icon {
    margin-left: -3px;
    padding: 6px 6px 6px 0px;
    font-size: 16px;
  }

}
</style>
